<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>动画</title>
    <style type="text/css">
      /* ************************************************************** */
      html:root {
        --box-width: 350px;
        --box-height: fit-content;
      }
      .demo-box.demo-box dl {
        width: clamp(800px, 70%, 1200px);
      }
      /* ************************************************************** */
      /* ************************************************************** */
      .box {
        height: 100px;
        color: #fff;
        background-color: red;
      }
      #case5-btn,
      #case8-btn,
      #case9-btn,
      #case11-btn {
        width: 100px;
        height: 40px;
      }

      .case4 {
        height: 100px;
        position: relative;
      }
      .case4 .box {
        position: absolute;
        left: 0;
        height: inherit;
        width: 100px;
        animation: right-out 0.5s infinite, fade-out 0.5s infinite;
      }
      @keyframes right-out {
        from {
          left: 0;
        }
        to {
          left: 100%;
        }
      }
      @keyframes fade-out {
        from {
          opacity: 1;
        }
        to {
          opacity: 0;
        }
      }
      #case5 {
        height: 80px;
        width: 100px;
        display: inline-block;
      }
      .case5 {
        border: 1px dashed red;
        animation: case5-background-color 2.5s 1.5s infinite;
      }
      @keyframes case5-background-color {
        from {
          background-color: black;
        }
        to {
          background-color: #fff;
        }
      }
      .case6 {
        height: 80px;
        width: 100px;
        display: inline-block;
        border: 1px dashed red;
        animation: case6-background-color 2.5s infinite;
      }
      @keyframes case6-background-color {
        0%,
        60% {
          background-color: black;
        }
        to {
          background-color: #fff;
        }
      }
      .case7 {
        margin-top: 20px;
        height: 80px;
      }
      .case7 i {
        display: inline-block;
        border-left: 10px solid slateblue;
        height: 4px;
        animation: case7 4s linear infinite alternate;
        margin: 0 1px;
      }
      /* .case7 i:nth-child(2) {
        animation-delay: 1s;
      }
      .case7 i:nth-child(3) {
        animation-delay: 2s;
      }
      .case7 i:nth-child(4) {
        animation-delay: 3s;
      } */
      .case7 i:nth-child(2) {
        animation-delay: -1s;
      }
      .case7 i:nth-child(3) {
        animation-delay: -2s;
      }
      .case7 i:nth-child(4) {
        animation-delay: -3s;
      }
      @keyframes case7 {
        to {
          transform: scaleY(10);
        }
      }
      .case8 {
        height: 80px;
        width: 100px;
        background-color: red;
        opacity: 0;
      }
      .case8.active {
        animation: case8 4s -1s linear;
      }
      @keyframes case8 {
        to {
          opacity: 1;
        }
      }

      .case9 {
        /* 让动画执行两次 */
        height: 50px;
        width: 150px;
        margin: 5px;
        display: inline-block;
        background-color: red;
        color: black;
        opacity: 0.1;
        vertical-align: bottom;
      }
      .case9.active {
        animation: case9 3s 2;
      }
      .case9.active.case9-directiion1 {
        /* 默认值 */
        animation-direction: normal;
      }
      .case9.active.case9-directiion2 {
        animation-direction: reverse;
      }
      .case9.active.case9-directiion3 {
        animation-direction: alternate;
      }
      .case9.active.case9-directiion4 {
        animation-direction: alternate-reverse;
      }
      @keyframes case9 {
        to {
          opacity: 1;
        }
      }

      .case10 {
        margin: 60px 0 0 60px;
        width: 20px;
        height: 20px;
        border-radius: 50%;
        border: 3px solid black;
        animation: case10 1s ease-in-out alternate infinite;
        transform-origin: 50% -200%;
        position: relative;
      }
      .case10::before {
        content: '';
        position: absolute;
        height: 40px;
        width: 3px;
        background-color: black;
        top: -40px;
        left: calc((100% - 3px) / 2);
      }
      @keyframes case10 {
        from {
          transform: rotate(40deg);
        }
        to {
          transform: rotate(-40deg);
        }
      }

      .case11 {
        width: 50px;
        height: 50px;
        background-color: red;
      }
      .case11.active {
        animation: case11 1s 0.5 forwards;
      }
      @keyframes case11 {
        to {
          opacity: 0;
        }
      }

      .case12-paused {
        animation-play-state: paused;
      }
      .case12-running {
        animation-play-state: running;
      }

      .case13-box-x {
        width: 810px;
        height: 50px;
        border: 1px solid black;
      }
      .case13-box-x > div {
        height: calc(100% / 3);
        width: 10px;
        background-color: red;
      }
      .case13-normal {
        animation: case13 3s infinite;
      }
      .case13-start {
        animation: case13 3s infinite steps(5, start);
      }
      .case13-end {
        animation: case13 3s infinite steps(5, end);
      }
      @keyframes case13 {
        to {
          transform: translateX(800px);
        }
      }
      /* ************************************************************** */
      /* ************************************************************** */
    </style>
  </head>
  <body>
    <!-- ------------------------------------------------------------->
    <!-- ------------------------------------------------------------->
    <header>
      <a href="./15-动画-transition.html">上一篇</a>
      <a href="./17-分栏布局.html">下一篇</a>
    </header>
    <!-- ------------------------------------------------------------->
    <!-- ------------------------------------------------------------->
    <section class="demo-box">
      <dl>
        <dt>animation</dt>
        <dd>
          <h4>基本使用</h4>
          animation: name | duration | timing-function | delay | iteration-count
          | direction | fill-mode | play-state
          <br />
          <br />
          animation支持多个动画，所以动画效果最好拆开书写。例如向右淡出，可以拆成向后和淡出两部分
          <pre><code class="language-scss">
animation: right-out 0.5s infinite, fade-out 0.5s infinite;
@keyframes right-out { ... }
@keyframes fade-out { ... }</code></pre>
          <div class="case4">
            <div class="box"></div>
          </div>
        </dd>
      </dl>
      <!-- *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*- -->
      <dl>
        <dd>
          <dt>@keyframes</dt>
          1、关键字form、to等同于 0% 和 100%
          <br />
          2、起止帧可以不设置
          <br />
          3、关键帧列表可以合并
          <pre><code class="language-scss">
@keyframes simple { 
    0%, 50%, 100% {
        opacity: 0
    }
    25%, 75% {
        opacity: 1
    }
 }</code></pre>
          4、关键帧书写规则无序
          <br />
          5、重复定义的关键帧覆盖规则同css
          <br />
          6、前后关键帧的属性可以不一致
          <br />
          7、!important无效，实际上动画本就是最高级，比前者等级更高（firfox除外）；但不能重置不支持动画的属性，例如display:
          none（正道的光）
        </dd>
      </dl>
      <!-- *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*- -->
      <dl>
        <dd>
          <dt>动画命名与&lt;custom-ident&gt;</dt>
          <ul>
            <li>任意字母（区分大小写）</li>
            <li>数字(0-9)</li>
            <li>短横线(-)</li>
            <li>下划线(_)</li>
            <li>转义字符(反斜杠\转义)</li>
            <li>unicode(反斜杠\后跟十六进制)</li>
          </ul>
          此外：
          <br />
          1、不能是css本身的关键字，如inhibit
          <br />
          2、不能以十进制数字开头，如2222ss
          <br />
          3、短横线开头时，后面第一个不能是十进制数字。如-22ss不合法， -sss合法
          <br />
          4、除了短横线和下划线，其他英文符号必须转义。如a.png不合法，a\.png合法
          <br />
          5、unicode转义记得后面跟一个空格。如\233 aa合法
          <br />
        </dd>
      </dl>
      <!-- *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*- -->
      <dl>
        <dd>
          <dt>负延时播放与即时播放效果</dt>
          1、延时动画只有第一次延时；若要对永久播放的动画做演示，需要每一次都设置
          <button id="case5-btn">添加延时动画</button>
          <br />
          <div id="case5"></div>
          <div class="case6"></div>
          <pre><code class="language-scss">
@keyframes simple {
    0%,60% {
        background-color: black;
    }
    to {
        background-color: #fff;
    }
}</code></pre>
          2、延时例子，音波图
          <div class="case7">
            <i></i>
            <i></i>
            <i></i>
            <i></i>
          </div>
          图中bar初始状态有一定高度，不符合预期。将延时改成负数即可（注释里），让动画即时播放
          <br />
          ps: 如何理解delay的负值？
          <br />
          例如-1s，即意味着从动画正常开始后的1s的状态开始。
          <br />
          例如opacity匀速4s，从0变化至1，delay设置-1s，则意味着动画直接跳转到原始动画的1s后，即表现为0.25变化到1的过程
          <br />
          <button id="case8-btn">演示样例</button>
          <div class="case8" id="case8"></div>
        </dd>
      </dl>
      <!-- *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*- -->
      <dl>
        <dd>
          <dt>animation-direction</dt>
          <button id="case9-btn">演示样例</button>
          <ul>
            <li>normal 正</li>
            <li>reverse 反</li>
            <li>alternate 正反循环</li>
            <li>alternate-reverse 反正循环</li>
          </ul>
          <div class="case9 case9-directiion1">normal</div>
          <div class="case9 case9-directiion2">reverse</div>
          <div class="case9 case9-directiion3">alternate</div>
          <div class="case9 case9-directiion4">alternate-reverse</div>
          <br />
          <strong>场景：摆钟</strong>
          <br />
          不要尝试用关键帧头尾相连来做，那根本不是现实中的钟摆行为。
          <div class="case10"></div>
          <pre><code class="language-scss">
animation: simple 1s ease-in-out alternate infinite;</code></pre>
        </dd>
      </dl>
      <!-- *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*- -->
      <dl>
        <dd>
          <dt>animation-iteration-count</dt>
          1、播放次数可以使用小数
          <div>
            <button id="case11-btn">播放0.5次</button>
            <div class="case11" id="case11"></div>
          </div>
          2、关键字 infinite 表示无限播放
          <br />
          3、值范围：非负
        </dd>
      </dl>
      <!-- *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*- -->
      <dl>
        <dd>
          <dt>animation-fill-mode</dt>
          该属性用来指定执行动画外的应用值
          <ul>
            <li>forwards，应用最后一帧的样式</li>
            <li>backwards，应用第一帧的样式</li>
            <li>
              none，默认值，表示结束开始都不会应用keyframs中规定的任何一帧
            </li>
            <li>both，</li>
          </ul>
          由于循环的存在，forwards停留的最后一帧因实际情况决定；而backwards的第一帧只和animation-direction有关
        </dd>
      </dl>
      <!-- *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*- -->
      <dl>
                <dd>
          <dt>暂停和重启动画</dt>
          <ul>
            <li>暂停： 使用animation-play-state: paused</li>
            <li>
              启动： 若是重启暂停的动画，使用animation-play-state:
              running，或去掉相关样式；要重新开始，则利用js重绘
            </li>
          </ul>
          <button id="case12-btn">暂停上面的摆钟</button>
        </dd>
      </dl>
      <!-- *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*- -->
      <dl>
        <dd>
          <dt>animation-timing-function</dt>
          函数分为cubic-bezier()和steps()
          <ul>
            <li>cubic-bezier，贝塞尔曲线</li>
            <li>
              steps，让动画不连续，只播放分段的那一帧。设置start抢先一步抬升，由于函数是阶梯状的（不可导），表现在画面上每一帧提前。函数表现如下图
              <img src="../../Source/animation-steps.png" height="400px" />
            </li>
          </ul>
          顺序为默认、start、end
          <div class="case13-box-x">
            <div class="case13-normal"></div>
            <div class="case13-start"></div>
            <div class="case13-end"></div>
          </div>
        </dd>
      </dl>
      <!-- *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*- -->
    </section>
    <!-- ------------------------------------------------------------->
    <!-- ------------------------------------------------------------->
    <link rel="stylesheet" href="./0-模板.css" />
    <link
      rel="stylesheet"
      href="../../Module/hightlight/styles/hybrid.min.css"
    />
    <script src="../../Module/hightlight/highlight.min.js"></script>
    <script>
      hljs.highlightAll()
      case5()
      case8()
      case9()
      case11()
      case12()
      function case5() {
        const btn = document.getElementById('case5-btn')
        btn.addEventListener('click', function () {
          const caseDom = document.getElementById('case5')
          caseDom.className = 'case5'
        })
      }
      function case8() {
        const btn = document.getElementById('case8-btn')
        btn.addEventListener('click', function () {
          const caseDom = document.getElementById('case8')
          caseDom.className = 'case8'
          setTimeout(() => {
            caseDom.className = 'case8 active'
          })
        })
      }
      function case9() {
        const btn = document.getElementById('case9-btn')
        btn.addEventListener('click', function () {
          const caseDoms = document.querySelectorAll('.case9')
          for (let i = 0; i < caseDoms.length; i++) {
            const item = caseDoms[i]
            item.className = `case9 case9-directiion${i + 1}`
            setTimeout(() => {
              item.className = `case9 case9-directiion${i + 1} active`
            })
          }
        })
      }
      function case11() {
        const btn = document.getElementById('case11-btn')
        btn.addEventListener('click', function () {
          const caseDom = document.getElementById('case11')
          caseDom.className = 'case11'
          setTimeout(() => {
            caseDom.className = 'case11 active'
          })
        })
      }
      function case12() {
        const btn = document.getElementById('case12-btn')
        btn.addEventListener('click', function () {
          const caseDom = document.getElementsByClassName('case10')[0]
          if (/case12-paused/.test(caseDom.className)) {
            caseDom.className = caseDom.className.replace('paused', 'running')
            btn.innerHTML = '暂停上面的摆钟'
          } else if (/case12-running/.test(caseDom.className)) {
            caseDom.className = caseDom.className.replace('running', 'paused')
            btn.innerHTML = '播放上面的摆钟'
          } else {
            caseDom.className += ' case12-paused'
            btn.innerHTML = '播放上面的摆钟'
          }
        })
      }
    </script>
  </body>
</html>
